require("ddzenum")
local cardtool = require "ddzgamelogic"
local filelog = require "filelog"
local tabletool = require "tabletool"
local table_insert = table.insert
local table_remove = table.remove
local math_floor = math.floor
local math_ceil = math.ceil

local ddzgamelogic = cardtool:new()

-- 类型补偿分数
local CardsTypeExtraPoints = {
    SINGLE 				= -2, 	-- 单张
    PAIR	 			= 0, 	-- 对子
    THREE 				= 3, 	-- 三张
    ONE_STRAIGHT 		= 8, 	-- 单顺(大于5张，每多一张增加2分)
    TWO_STRAIGHT 		= 12, 	-- 连对(大于3对，每多一对增加3分)
    THREE_STRAIGHT		= 14, 	-- 三顺(大于2顺，每多一THREE增加4分)
    THREE_ONE			= 6, 	-- 三带一
    THREE_PAIR 			= 6,    -- 三带二
    THREE_WING_ONE 		= 20,  	-- 飞机带翅膀(单)(大于2 THREE_ONE，每多一THREE_ONE增加8分)
    THREE_WING_PAIR 	= 20, 	-- 飞机带翅膀(双)(大于2 WING_PAIR，每多一THREE_PAIR增加10分)
    FOUR_TWO_ONE 		= 8,  	-- 四带二张
    FOUR_TWO_PAIR 		= 12, 	-- 四代两对
    BOMB				= 22, 	-- 炸弹
    ROCKET				= 24, 	-- 火箭(王炸)
}

-- 类型牌中最大值积一个分数
local CardMaxValuePoints = {
    [3] = -6,
    [4] = -4,
    [5] = -2,
    [6] = -1,
    [7] = 0,
    [8] = 1,
    [9] = 2,
    [10] = 3,
    [11] = 4,   -- J
    [12] = 5,   -- Q
    [13] = 6,   -- K
    [14] = 7,  -- A
    [15] = 10,  -- 2
    [16] = 11,  -- JOKER
    [17] = 12,  -- JOKER
}

local robot = {}
function robot:new(obj)
	local entity = obj or {}
	setmetatable(entity, self)
	self.__index = self
	return entity
end

--[[
local container = {
    single = {},
    pair   = {},
    three  = {},
    sitiao = {}
}
--]]

-- 精确计算手牌分数
-- 分数 = 最大牌值分数 + 类型补偿分数 + 牌数量分数
function robot:calcardspoints(cards, isseparated)
    filelog.debug("cards = ", #cards)
    for i,v in ipairs(cards) do
        local val = ddzgamelogic.get_card_value(v)
        if val == 11 then val = "J" end
        if val == 12 then val = "Q" end
        if val == 13 then val = "K" end
        if val == 14 then val = "A" end
        if val == 15 then val = "2" end
        if val == 16 then val = "小JOKER" end
        if val == 17 then val = "大JOKER" end
        print(v,val)
    end
    local cardscontainer = ddzgamelogic.extract(cards)
    local points = 0
    local maxpoints = 0

    local single = {}
    local pair = {}
    local three = {}
    local bigcards = {}

    local preval = nil
    local currval = nil
    local count = 0

    -- cardscontainer已经从大到小排序
    -- filelog.debug("cardscontainer = ", cardscontainer)

    -- 寻找炸弹
    for i = 1, #cardscontainer.sitiao , 4 do
        currval = ddzgamelogic.get_card_value(cardscontainer.sitiao[i])
        points = points + CardMaxValuePoints[currval] + CardsTypeExtraPoints.BOMB -- + 4
        count = count + 1
    end
    if count >= 2 then
        points = points + (count - 1) * 8
    end

    filelog.debug("炸弹 points = ", points)
    preval = nil
    currval = nil
    count = 1

    -- 寻找连对，剩余对牌可用于补贴飞机，三带对
    local paircontainer = {}
    for i = 1, #cardscontainer.pair, 2 do
        currval = ddzgamelogic.get_card_value(cardscontainer.pair[i])
        if currval < 15 then
            if preval then
                if preval - currval == count then
                    count = count + 1
                    table_insert(paircontainer[preval], currval)
                else
                    preval = currval
                    paircontainer[preval] = {}
                    table_insert(paircontainer[preval], currval)
                    count = 1
                end
            else
                preval = currval
                paircontainer[preval] = {}
                table_insert(paircontainer[preval], currval)
                count = 1
            end
        else
            table_insert(pair, currval)
            table_insert(pair, currval)
        end
    end
    for cardval, members in pairs(paircontainer) do
        if #members < 3 then
            for _, v in ipairs(members) do
                table_insert(pair, v)
                table_insert(pair, v)
            end
        else
            points = points + CardMaxValuePoints[cardval] + CardsTypeExtraPoints.TWO_STRAIGHT
            points = points + (#members - 3) * 3 -- + #members * 2
        end
    end
    table.sort(pair, function (l, r)
        return l > r
    end)
    filelog.debug("连对 points = ", points)
    preval = nil
    currval = nil
    count = 1

    -- 寻找顺子，剩余单排可用于补贴飞机，三带一
    local singlecontainer = {}
    for i = 1, #cardscontainer.single do
        currval = ddzgamelogic.get_card_value(cardscontainer.single[i])
        if currval < 15 then
            if preval then
                if preval - currval == count then
                    count = count + 1
                    table_insert(singlecontainer[preval], currval)
                else
                    preval = currval
                    singlecontainer[preval] = {}
                    table_insert(singlecontainer[preval], currval)
                    count = 1
                end
            else
                preval = currval
                singlecontainer[preval] = {}
                table_insert(singlecontainer[preval], currval)
                count = 1
            end
        elseif currval >= 16 then
            table_insert(bigcards, currval)
        else
            table_insert(single, currval)
        end
    end
    for cardval, members in pairs(singlecontainer) do
        if #members < 5 then
            for _, v in ipairs(members) do
                table_insert(single, v)
            end
        else
            points = points + CardMaxValuePoints[cardval] + CardsTypeExtraPoints.ONE_STRAIGHT
            points = points + (#members - 5) * 2 -- + #members
        end
    end
    table.sort(single, function (l, r)
        return l > r
    end)
    filelog.debug("顺子 points = ", points)
    preval = nil
    currval = nil
    count = 1

    -- 寻找飞机
    local tmppair = {}
    local threecontainer = {}
    for i = 1, #cardscontainer.three, 3 do
        currval = ddzgamelogic.get_card_value(cardscontainer.three[i])
        if currval < 15 then
            if preval then
                if preval - currval == count then
                    count = count + 1
                    table_insert(threecontainer[preval], currval)
                else
                    preval = currval
                    threecontainer[preval] = {}
                    table_insert(threecontainer[preval], currval)
                    count = 1
                end
            else
                preval = currval
                threecontainer[preval] = {}
                table_insert(threecontainer[preval], currval)
                count = 1
            end
        else
            table_insert(three, currval)
            table_insert(three, currval)
            table_insert(three, currval)
        end
    end
    for cardval, members in pairs(threecontainer) do
        if #members >= 2 then   -- 飞机
            if #single >= #members then -- 飞机带单
                for _, v in ipairs(members) do
                    table.remove(single)
                end
                points = points + CardMaxValuePoints[cardval] + CardsTypeExtraPoints.THREE_WING_ONE
                points = points + (#members - 2) * 8 --+ #members * 4
            elseif #pair >= #members then
                if #pair >= #members * 2 then   -- 飞机带对儿
                    for _, v in ipairs(members) do
                        table.remove(pair)
                        table.remove(pair)
                    end
                    points = points + CardMaxValuePoints[cardval] + CardsTypeExtraPoints.THREE_WING_PAIR
                    points = points + (#members - 2) * 10 -- + #members * 5
                else    -- 飞机带单
                    for _, v in ipairs(members) do
                        table.remove(pair)
                    end
                    points = points + CardMaxValuePoints[cardval] + CardsTypeExtraPoints.THREE_WING_ONE
                    points = points + (#members - 2) * 8 -- + #members * 4
                end
            else    -- 飞机不带，即为三顺
                points = points + CardMaxValuePoints[cardval] + CardsTypeExtraPoints.THREE_STRAIGHT
                points = points + (#members - 2) * 3 -- + #members * 3
            end
        else
            local cardval = members[1]
            if cardval < 14 then
                table_insert(tmppair, cardval)
            end

            -- if #single >= 1 then
            --     table.remove(single)
            --     points = points + CardMaxValuePoints[cardval] + CardsTypeExtraPoints.THREE_ONE
            --     -- points = points + 4
            -- elseif #pair >= 2 then
            --     table.remove(pair)
            --     table.remove(pair)
            --     points = points + CardMaxValuePoints[cardval] + CardsTypeExtraPoints.THREE_PAIR
            --     -- points = points + 5
            -- else
            --     points = points + CardMaxValuePoints[cardval] + CardsTypeExtraPoints.THREE
            --     -- points = points + 3
            -- end
        end
    end
    filelog.debug("飞机 points = ", points)

    preval = nil
    currval = nil
    count = 1

    ------------- 拆分三条组合连对 -------------
    for i = 1, #pair, 2 do
        if pair[i] <= 14 then
            table_insert(tmppair, pair[i])
        end
    end
    table.sort(tmppair, function (l, r)
        return l > r
    end)

    local tmppaircontainer = {}
    for i = 1, #tmppair do
        currval = tmppair[i]
        if preval then
            if preval - currval == count then
                count = count + 1
                table_insert(tmppaircontainer[preval], currval)
            else
                preval = currval
                tmppaircontainer[preval] = {}
                table_insert(tmppaircontainer[preval], currval)
                count = 1
            end
        else
            preval = currval
            tmppaircontainer[preval] = {}
            table_insert(tmppaircontainer[preval], currval)
            count = 1
        end
    end
    for cardval, members in pairs(tmppaircontainer) do
        if #members >= 3 then
            points = points + CardMaxValuePoints[cardval] + CardsTypeExtraPoints.TWO_STRAIGHT
            points = points + (#members - 3) * 3 -- + #members * 2

            for n = 1, #members do
                if threecontainer[members[n]] then
                    table_insert(single, members[n])
                    threecontainer[members[n]] = nil
                else
                    for n = 1, 2 do
                        for k, v in ipairs(pair) do
                            if v == members[n] then
                                table_remove(pair, k)
                                break
                            end
                        end
                    end
                end
            end
        end
    end
    filelog.debug("三张拆分连对 points = ", points)

    preval = nil
    currval = nil
    count = 1

    table.sort(single, function (l, r)
        return l > r
    end)
    for cardval, members in pairs(threecontainer) do
        if #members < 2 then
            if #single >= 1 and single[1] < 15 then
                table.remove(single)
                points = points + CardMaxValuePoints[cardval] + CardsTypeExtraPoints.THREE_ONE
                -- points = points + 4
            elseif #pair >= 2 and pair[1] < 15 and pair[2] < 15 then
                table.remove(pair)
                table.remove(pair)
                points = points + CardMaxValuePoints[cardval] + CardsTypeExtraPoints.THREE_PAIR
                -- points = points + 5
            else
                points = points + CardMaxValuePoints[cardval] + CardsTypeExtraPoints.THREE
                -- points = points + 3
            end
        end
    end

    filelog.debug("三带 points = ", points)
    preval = nil
    currval = nil
    count = 1

    -------- 还有多余的对牌，单牌计算分数 --------
    for i = 1, #three do
        points = points + CardMaxValuePoints[three[i]] - (3 - i) * 6 -- 0 + 6 + 12
    end
    filelog.debug("三张2 points = ", points)

    for i = 1, #pair, 2 do
        points = points + CardMaxValuePoints[pair[i]] + CardsTypeExtraPoints.PAIR
        -- points = points + 2
    end
    filelog.debug("对子 points = ", points)
    for i = 1, #single do
        points = points + CardMaxValuePoints[single[i]] + CardsTypeExtraPoints.SINGLE
    end
    filelog.debug("单牌 points = ", points)

    if #bigcards == 2 then
        points = points + CardsTypeExtraPoints.ROCKET
    elseif #bigcards == 1 then
        points = points + CardMaxValuePoints[bigcards[1]] + CardsTypeExtraPoints.SINGLE
    end
    filelog.debug("JOKER points = ", points)

    maxpoints = points

    if isseparated then
        filelog.debug("separated calcardspoints = ", maxpoints)
        return maxpoints
    end

    -- 计算提取出顺子后加上剩余牌分数，如果分数更高则为最高分数
    local allsinglecontainer = {}
    local allsingleindexcontainer = {}
    local leftcards = {}
    local seppoints = 0
    for i = #cards, 1, -1 do
        currval = ddzgamelogic.get_card_value(cards[i])
        if currval < 15 then
            local isleft = true
            for _, members in ipairs(allsingleindexcontainer) do
                if ddzgamelogic.get_card_value(members[#members]) + 1 == currval then
                    table_insert(members, cards[i])
                    isleft = false
                    break
                end
            end
            if isleft then
                table_insert(allsingleindexcontainer, {cards[i]})
            end
        else
            table_insert(leftcards, cards[i])
        end
    end

    local isempty = true
    local maxlen, maxlenidx = 0, 0
    for k, members in ipairs(allsingleindexcontainer) do
        if #members < 5 then
            for _, index in ipairs(members) do
               table_insert(leftcards, index)
            end
        else
            allsinglecontainer[k] = {}
            for _, index in ipairs(members) do
                table_insert(allsinglecontainer[k], ddzgamelogic.get_card_value(index))
            end
            if #members > maxlen then
                maxlen = #members
                maxlenidx = k
            end
            isempty = false
        end
    end

    if isempty then
        filelog.trace("calcardspoints no separate = ", maxpoints)
        filelog.print("---------------------------------------------------------------------")
        return maxpoints
    else
        filelog.trace("befor separate maxpoints = ", maxpoints)
        filelog.debug("allsinglecontainer = ", allsinglecontainer)
    end

    -- 先取最长顺子，逐一减小计算剩余手牌分数，取分数最大时的顺子
    if maxlen >= 6 then
        for idx, members in pairs(allsinglecontainer) do
            if idx ~= maxlenidx then
                seppoints = seppoints + CardMaxValuePoints[members[#members]] + CardsTypeExtraPoints.ONE_STRAIGHT
                seppoints = seppoints + (#members - 5) * 2 -- + #members
            end
        end

        local tmpseppoints = 0
        seppoints = seppoints + CardMaxValuePoints[allsinglecontainer[maxlenidx][maxlen]] + CardsTypeExtraPoints.ONE_STRAIGHT
        seppoints = seppoints + (maxlen - 5) * 2 -- + #members
        print("------------s base------------")
        table.sort(leftcards, function (l, r)
            return l > r
        end)
        seppoints = seppoints + self:calcardspoints(leftcards, true)
        print("------------e base------------")
        filelog.trace("base seppoints = ", seppoints)
        
        for i = 1, maxlen - 5 do
            local tmpleftcards = tabletool.deepcopy(leftcards)
            local tmpseppoints = 0
            tmpseppoints = tmpseppoints + CardMaxValuePoints[allsinglecontainer[maxlenidx][maxlen-i]] + CardsTypeExtraPoints.ONE_STRAIGHT
            tmpseppoints = tmpseppoints + (maxlen - 5) -- + #members
            for j = 1, i do
                table_insert(tmpleftcards, allsingleindexcontainer[maxlenidx][maxlen-j+1])
            end
            print("------------s from last------------")
            table.sort(tmpleftcards, function (l, r)
                return l > r
            end)
            tmpseppoints = tmpseppoints + self:calcardspoints(tmpleftcards, true)
            print("------------e from last------------")

            filelog.debug("the " .. i .. " time:", "from last tmpseppoints = ", tmpseppoints)
            -- seppoints = tmpseppoints > seppoints and tmpseppoints or seppoints
            if tmpseppoints > seppoints then    -- 这里可以增加记录最大分数时的顺子
                seppoints = tmpseppoints
            end
        end

        for i = 1, maxlen - 5 do
            local tmpleftcards = tabletool.deepcopy(leftcards)
            local tmpseppoints = 0
            tmpseppoints = tmpseppoints + CardMaxValuePoints[allsinglecontainer[maxlenidx][maxlen]] + CardsTypeExtraPoints.ONE_STRAIGHT
            tmpseppoints = tmpseppoints + (maxlen - 5) * 2 -- + #members
            for j = 1, i do
                table_insert(tmpleftcards, allsingleindexcontainer[maxlenidx][j])
            end
            print("------------s form first------------")
            table.sort(tmpleftcards, function (l, r)
                return l > r
            end)
            tmpseppoints = tmpseppoints + self:calcardspoints(tmpleftcards, true)
            print("------------e from first------------")

            filelog.debug("the " .. i .. " time:", "from first tmpseppoints = ", tmpseppoints)
            -- seppoints = tmpseppoints > seppoints and tmpseppoints or seppoints
            if tmpseppoints > seppoints then    -- 这里可以增加记录最大分数时的顺子
                seppoints = tmpseppoints
            end
        end
        filelog.trace("result seppoints = ", seppoints)
--[=[这个可以用作简单机器人
        seppoints = seppoints + CardMaxValuePoints[allsinglecontainer[maxlenidx][maxlen]] + CardsTypeExtraPoints.ONE_STRAIGHT
        seppoints = seppoints + (maxlen - 5) * 2 -- + #members
        local tmpseppoints = 0
        tmpseppoints = tmpseppoints + CardMaxValuePoints[allsinglecontainer[maxlenidx][5]] + CardsTypeExtraPoints.ONE_STRAIGHT
        for i = 1, maxlen - 5 do
            table_insert(leftcards, allsingleindexcontainer[maxlenidx][maxlen-i+1])
        end
        print("------------s------------")
        table.sort(leftcards, function (l, r)
            return l > r
        end)
        tmpseppoints = tmpseppoints + self:calcardspoints(leftcards, true)
        print("------------e------------")
        filelog.debug("tmpseppoints = ", tmpseppoints)
        seppoints = tmpseppoints > seppoints and tmpseppoints or seppoints
--]=]
    elseif maxlen == 5 then
        -- 细分多个顺子的情况，可以，但没必要
        for idx, members in pairs(allsinglecontainer) do
            seppoints = seppoints + CardMaxValuePoints[members[#members]] + CardsTypeExtraPoints.ONE_STRAIGHT
            seppoints = seppoints + (#members - 5) * 2 -- + #members
        end
        table.sort(leftcards, function (l, r)
            return l > r
        end)
        local leftcardscontainer = ddzgamelogic.extract(leftcards)
        if #leftcardscontainer.single - #cardscontainer.single > 0 then
            seppoints = seppoints
            filelog.warn("more single, no need to separate!")
        else
            if #leftcardscontainer.pair - #cardscontainer.pair > 0 then
                seppoints = seppoints
                filelog.warn("more pair, no need to separate!")
            else
                print("------------s 5len------------")
                seppoints = seppoints + self:calcardspoints(leftcards, true)
                print("------------e 5len------------")

                filelog.trace("result seppoints = ", seppoints)
            end
        end
    end

    preval = nil
    currval = nil
    count = 1
--[=[如果单牌或者对子变多，则直接用前面的最大分数。这个可以用作简单机器人
    table.sort(leftcards, function (l, r)
        return l > r
    end)
    local leftcardscontainer = ddzgamelogic.extract(leftcards)
    if #leftcardscontainer.single - #cardscontainer.single > 0 then
        maxpoints = maxpoints
        filelog.warn("more single, no need separate!")
    else
        if #leftcardscontainer.pair - #cardscontainer.pair > 0 then
            maxpoints = maxpoints
            filelog.warn("more pair, no need separate!")
        else
            print("------------s------------")
            seppoints = seppoints + self:calcardspoints(leftcards, true)
            print("------------e------------")
            filelog.debug("seppoints = ", seppoints)
        end
    end
--]=]
    maxpoints = seppoints > maxpoints and seppoints or maxpoints
    filelog.trace("calcardspoints maxpoints = ", maxpoints)
    filelog.print("---------------------------------------------------------------------")
    return maxpoints
end

-- 大体上，按照既定出牌优先级，取剩余分数最大的出牌方式
-- 根据外部条件，细分并优化出牌方式
function robot:playcards(cards, cardsnum1, cardsnum2)
    
end

-- 寻找所有可能的跟牌方式，取剩余分数最大的跟牌方式
function robot:followcards()
    
end

-- 操作类型
local actions = {
    [EActionType.ACTION_TYPE_JIAODIZHU] = function()  	-- 叫地主

    end,
    [EActionType.ACTION_TYPE_QIANGDIZHU] = function()		-- 抢地主

    end,
    [EActionType.ACTION_TYPE_CHUPAI] = function(self, cards, cardsnum1, cardsnum2)     		-- 出牌
        return self:playcards(cards, cardsnum1, cardsnum2)
    end,
    [EActionType.ACTION_TYPE_FOLLOW_CHUPAI] = function() 	-- 跟牌

    end,
    [EActionType.ACTION_TYPE_CHECK] = function()			-- 让牌

    end,
    [EActionType.ACTION_TYPE_BUJIAO_DIZHU] = function()	-- 不叫地主

    end,
    [EActionType.ACTION_TYPE_BUQIANGDIZHU] = function()	-- 不抢地主

    end,
    [EActionType.ACTION_TYPE_DODOUBLE] = function()  	-- 加倍

    end,
}

function robot:action(actiontype, cards, cardsnum1, cardsnum2)
    if actions[actiontype] then
        return actions[actiontype](self, cards, cardsnum1, cardsnum2)
    end
    filelog.warn("undefined action!")
    return false
end

return robot